﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TreeSharp;
using Styx.Combat.CombatRoutine;
using Styx.Logic.Combat;
using Styx.WoWInternals;
using FelMaster.Dev;
using FelMaster.Classes;
using FelMaster.Classes.Warlock;
using Styx;
using System.Drawing;
using Styx.Logic.BehaviorTree;
using FelMaster.ClassButton;
using Styx.Logic.Pathing;

namespace FelMaster
{
    public class FelMaster : CombatRoutine
    {
        public override Styx.Combat.CombatRoutine.WoWClass Class
        {
            get { return StyxWoW.Me.Class; }
        }

        public override void OnButtonPress()
        {
            Settings.Display(this);
            //SpellLockWatcher.Display();
            //AreaDebugger.Display();
            //SelectClass.Display(this);
        }
        public override bool WantButton
        {
            get
            {
                return true;
            }
        }

        public static readonly Version Version = new Version(1, 2, 1);

        public override string Name
        {
            get { return "FelMaster " + Version; }
        }

        private TalentBase talents = null;
        private WoWStats stats = new WoWStats();

        private Composite movingFacingBehavior;

        private void Log(string msg, params object[] a) { Styx.Helpers.Logging.Write(Color.PeachPuff, msg, a); }

        public override void Initialize()
        {
            BotEvents.OnBotStarted += OnStarted;
            BotEvents.OnBotStopped += OnStopped;

            movingFacingBehavior = new Sequence(
                //target check
                new DecoratorContinue(x => ObjectManager.Me.CurrentTarget == null,
                    new Sequence(
                        new TreeSharp.Action(a => Log("No target!")),
                        new Decorator(x => SettingsFile.Instance.CurrentMode_HandleMovement,
                            new TreeSharp.Action(delegate {
                                try { GroupBase.Instance.MostFocusedUnit.unit.Target(); }
                                catch { }
                            })
                        )
                    )
                ),

                //line of sight check
                new DecoratorContinue(x => !ObjectManager.Me.CurrentTarget.InLineOfSight,
                    new Sequence(
                        new TreeSharp.Action(a => Log("Target not in LoS. Moving closer.")),
                        new TreeSharp.Action(a => Navigator.MoveTo(ObjectManager.Me.CurrentTarget.Location))
                    )
                ),

                //range check & moving
                new DecoratorContinue(x => !ObjectManager.Me.IsMoving && ObjectManager.Me.CurrentTarget.InLineOfSight && SimCraftBase.Instance.DistanceToTargetBoundingBox() < ActiveTalentTree.CombatMinDistance,
                    new Sequence(
                        new TreeSharp.Action(a => Log("Too close of target. Moving backward.")),
                        new TreeSharp.Action(a => WoWMovement.Move(WoWMovement.MovementDirection.Backwards))
                    )
                ),
                new DecoratorContinue(x => !ObjectManager.Me.IsMoving && ObjectManager.Me.CurrentTarget.InLineOfSight && SimCraftBase.Instance.DistanceToTargetBoundingBox() > ActiveTalentTree.CombatMaxDistance,
                    new Sequence(
                        new TreeSharp.Action(a => Log("Too far away of target. Moving forward.")),
                        new TreeSharp.Action(a => Navigator.MoveTo(ObjectManager.Me.CurrentTarget.Location))
                    )
                ),
                new DecoratorContinue(x => ObjectManager.Me.IsMoving &&
                                            ObjectManager.Me.CurrentTarget.InLineOfSight &&
                                            SimCraftBase.Instance.DistanceToTargetBoundingBox() >= ActiveTalentTree.CombatMinDistance &&
                                            SimCraftBase.Instance.DistanceToTargetBoundingBox() <= ActiveTalentTree.CombatMaxDistance,
                    new Sequence(
                        new TreeSharp.Action(a => Log("Target range ok. Stop moving.")),
                        new TreeSharp.Action(a => WoWMovement.MoveStop())
                    )
                ),

                //facing
                new TreeSharp.Action(a => ObjectManager.Me.CurrentTarget.Face())
            );
        }

        private void OnStarted(object o)
        {
            stats.Init();

            LuaChannel.Instance.Bind("burst more", a => SimCraftBase.Instance.SetBurstLevel(SimCraftBase.Instance.BurstLevel + 1));
            LuaChannel.Instance.Bind("no burst", a => SimCraftBase.Instance.SetBurstLevel(0));

            LuaChannel.Instance.BindEvents();
            LuaChannel.Instance.AddAllUserMacros();
        }
        private void OnStopped(object o)
        {
            stats.PrintReport();
            stats.Destroy();

            LuaChannel.Instance.RemoveAllUserMacros();
            LuaChannel.Instance.UnbindEvents();
        }

        protected TalentBase ActiveTalentTree
        {
            get
            {
                if (talents == null)
                {
                    SelectClass.Display(this);
                    TreeRoot.Stop();
                }
                return talents;
            }
        }
        public void SetTalentTree(TalentBase tb)
        {
            Log("FelMaster: Changed rotation to " + tb.Name);
            Log(tb.Help);
            talents = tb;
        }

        public override void Pulse()
        {
            ObjectManager.Update();
            AuraTranslator.Instance.Pulse(20);
            /*
             * WIP stuff
             * ManageOracle();
            HealableUnit.Pulse();*/
        }

        public enum OracleWatchMode
        {
            Healer,
            DPS,
            Tank
        }
        public static OracleWatchMode OracleWatchFlags = OracleWatchMode.DPS;

        private void ManageOracle()
        {
            if (OracleWatchFlags == OracleWatchMode.Healer)
            {
                UnitOracle.WatchUnit(ObjectManager.Me, UnitOracle.Watch.HealthVariance);
                if (ObjectManager.Me.IsInRaid)
                {
                    ObjectManager.Me.RaidMembers.ForEach(x => UnitOracle.WatchUnit(x, UnitOracle.Watch.HealthVariance));
                }
                else if (ObjectManager.Me.IsInParty)
                {
                    ObjectManager.Me.PartyMembers.ForEach(x => UnitOracle.WatchUnit(x, UnitOracle.Watch.HealthVariance));
                }
            }
            else if (OracleWatchFlags == OracleWatchMode.DPS)
            {
                UnitOracle.WatchUnit(ObjectManager.Me, UnitOracle.Watch.HealthVariance);
            }
            else if (OracleWatchFlags == OracleWatchMode.Tank)
            {
                UnitOracle.WatchUnit(ObjectManager.Me, UnitOracle.Watch.HealthVariance);
                if (ObjectManager.Me.IsInRaid)
                {
                    ObjectManager.Me.RaidMembers.ForEach(x => UnitOracle.WatchUnit(x, UnitOracle.Watch.HealthVariance));
                }
                else if (ObjectManager.Me.IsInParty)
                {
                    ObjectManager.Me.PartyMembers.ForEach(x => UnitOracle.WatchUnit(x, UnitOracle.Watch.HealthVariance));
                }
            }

            //tick
            UnitOracle.Pulse();
        }

        public Composite Rotation
        {
            get
            {
                Composite rotation = null;
                switch (GroupBase.Instance.Group)
                {
                    case GroupBase.GroupType.PARTY:
                    case GroupBase.GroupType.RAID:
                        if (GroupBase.Instance.Logic == GroupBase.GroupLogic.PVE)
                        {
                            rotation = ActiveTalentTree.PVERotation;
                        }
                        else
                        {
                            rotation = ActiveTalentTree.PVPRotation;
                        }
                        break;

                    case GroupBase.GroupType.SINGLE:
                    default:
                        rotation = ActiveTalentTree.SingleRotation;
                        break;
                }

                return new Sequence(
                    new DecoratorContinue(x => SettingsFile.Instance.CurrentMode_HandleMovement, movingFacingBehavior),
                    new DecoratorContinue(x => ObjectManager.Me.CurrentTarget != null, rotation)
                );
            }
        }
        public Composite Buffs
        {
            get
            {
                return new PrioritySelector(
                    ActiveTalentTree.Buffs,
                    //runs combat rotation for healers even out of combat
                    new Decorator(x => !StyxWoW.Me.Combat && ActiveTalentTree.GetType() == typeof(HealerTalentBase),
                        Rotation
                    )
                );
            }
        }

        public override Composite PullBehavior { get { return Rotation; } }
        public override double? PullDistance
        {
            get
            {
                return ActiveTalentTree.CombatMaxDistance;
            }
        }
        public override Composite CombatBehavior { get { return Rotation; } }
        public override Composite CombatBuffBehavior { get { return Buffs; } }
        public override Composite PreCombatBuffBehavior { get { return Buffs; } }
        public override Composite RestBehavior { get { return Buffs; } }
    }
}
